/*
 * Copyright (C) 2011 : Gilles Coomans 
 * 
 * This file is part of QuintEssence.
 * QuintEssence is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * QuintEssence is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with QuintEssence.  If not, see <http://www.gnu.org/licenses/>.
 */
package net.exprom.qe.fields;
//import net.exprom.qe.IQELayerable;
import net.exprom.qe.fields.QEField;
import net.exprom.qe.QECore;
import net.exprom.qe.QEErrors;
import net.exprom.qe.QEStack;
import net.exprom.qe.QETools;
/**
 * ...
 * @author Gilles Coomans
 */

class QELeaf extends QEField
{		
	public var _value:Dynamic;
	public var evaluating:Bool;
	// metaMeta
	//public var xmlPlace:String;
	//public var evaluable:Bool;
	//public var valueType:Dynamic;
	//public var defaultValue:Dynamic;
	//public var valuesSet:Array<Dynamic>;		// les contraintes de valeurs : pour l'instant une array simple de valeur du meme type que celui donné par "type"
	//public var multivaluable:Bool;			//multivaluation possible

	public function new(name:String, parent:QEStack, params:Dynamic = null) 
	{
		super(name, parent, params);
		evaluating = false;
		fieldType = QEFT_LEAF;
		//_________________________________
	}	
	
	override private function createParamStruct():Dynamic
	{
		parameters = {
			visibility:QEFV_PUBLIC, 
			fixAfterValuation:true, 
			clonable:true, 
			removable:true,
			xmlPlace:null,
			finalRequired:false,
			layerRequired:false, 
			customCall: { },
			finaliseMetas:false,
			valuesSet:[],
			defaultValue : null,
			multivaluable : false,
			evaluable : false,
			valueType : null
		};
	}
	
	override public function applyParameters(params:Dynamic, up:Bool = true, commonOnly:Bool = false):Void 
	{
		super.applyParameters(params, up, commonOnly);
		if (up)
		{
			if (Reflect.hasField(params, "valuesSet")) 
				QETools.mergeArray(parameters.valuesSet, params.valuesSet);
			if (Reflect.hasField(params, "defaultValue")) 
				parameters.defaultValue  = params.defaultValue;
			if (Reflect.hasField(params, "multivaluable")) 
				parameters.multivaluable  = params.multivaluable;
			if (Reflect.hasField(params, "valueType")) 
				parameters.valueType  = params.valueType;
			if (Reflect.hasField(params, "evaluable")) 
				parameters.evaluable  = params.evaluable;
		}
		if (Reflect.hasField(params, "_value") && (up || !setted)) 
				setValue(params._value);
	}
	
	
	public function value(fix:Bool = false):Dynamic
	{
		if (parameters.evaluable == false)
		{
			//trace(path + " get value : not evaluable !");
			if (setted)
				return _value;
			else
				return parameters.defaultValue;
		}
		//trace(path + " : get value : evaluable");
		if (evaluated)
			return _value;
		var toEvaluate:Dynamic = parameters.defaultValue;
		if (setted)
			toEvaluate = _value;
				
		if (Reflect.isFunction(toEvaluate))
		{
			if (evaluating)
				throw "Error when fixing evaluables : cycle in calls detected : aborting";
			evaluating = true;
			var context = {root:rootContext, parent:parent,  metas:null, field:this, parameters:this.parameters };
			if (hasSettedMetas())
				context.metas = getMetasStack();
			var result = null;
			try{
				result = toEvaluate(context);
				if (fix)
				{
					_value = result;
					evaluated = true;
					setted = true;
				}
			}catch (e:Dynamic)
			{
				QEErrors.addError("Error when trying to evaluate leaf : " + path + " - error : " + Std.string(e));
				return null;
			}
			evaluating = false;	
			return result;
		}
		return toEvaluate;
	}
	
	public function setValue(val:Dynamic)
	{
		if(Reflect.hasField(parameters.customCall, "setValue")) 
			_value = parameters.customCall.setValue(this, val);
		else
			_value = val;
		setted = true;
	}
	
	override public function clone(cloned:Dynamic = null):Dynamic 
	{
		if (cloned == null)
			cloned = new QELeaf(name, null);
		return super.clone(cloned);
	}
	
	override public function compilField(field:QEField, up:Bool = true, commonOnly:Bool = false):Void 
	{
		super.compilField(field, up, commonOnly);
		if(up && field.setted)
		{
			_value = untyped field._value;
		}
	}

	override public function validate():Bool 
	{
		if (!setted)
			return true;
		var ok = true;
		if (hasSettedMetas())
			ok = metasStack.validate();
		return ok && QECore.typeValidator.validate(this);
	}
	
	override public function fixEvaluables():Void 
	{
		value(true);
		if (hasSettedMetas())
			getMetasStack().fixEvaluables();
	}
	
	override public function resetLeafs():Void 
	{
		super.resetLeafs();
		_value = null;
	}
}